package cn.openbiotoken.android.facetoken;

import android.util.Log;

import androidx.annotation.NonNull;

import com.nnf.nnfkitlib.KitDetection;
import com.nnf.nnfkitlib.KitInit;
import com.nnf.nnfkitlib.KitRecognition;
import com.nnf.nnfkitlib.NNF_ActiveInfo;
import com.nnf.nnfkitlib.NNF_Context;
import com.nnf.nnfkitlib.NNF_DETECTIONMODE;
import com.nnf.nnfkitlib.NNF_DEVICE;
import com.nnf.nnfkitlib.NNF_Feature;
import com.nnf.nnfkitlib.NNF_Function;
import com.nnf.nnfkitlib.NNF_RESULT;

public class RecognitionContext {

    private RecognitionContext() {
        initializer = KitInit.getInstance();
        activation = new NNF_ActiveInfo();
        final NNF_RESULT activationResult = initializer.GetActivationInfo(activation);
        logResult(activationResult, "constructor", "Get Activation Info");

        detector = KitDetection.getInstance();
        recognizer = KitRecognition.getInstance();
        session = new NNF_Context();
        function = new NNF_Function();

        detectionMode = NNF_DETECTIONMODE.IMAGE;
        device = NNF_DEVICE.CPU;
    }

    @NonNull
    private final KitInit initializer;

    @NonNull
    private final NNF_ActiveInfo activation;

    @NonNull
    private final KitDetection detector;

    @NonNull
    private final KitRecognition recognizer;

    @NonNull
    private final NNF_Context session;

    @NonNull
    private final NNF_Function function;

    @NonNull
    private NNF_DETECTIONMODE detectionMode;

    private int threadNumber;

    private float faceDetectThreshold;

    private int maxnum;

    private int minface;

    @NonNull
    private NNF_DEVICE device;

    private int deviceIndex;

    public void initialize() {
        final NNF_RESULT result = initializer.InitContext(session, function, detectionMode, threadNumber, faceDetectThreshold,
                maxnum, minface, device, deviceIndex);
        logResult(result, "initialize", "Initialize Context");
    }

    public float compareFeatures(@NonNull final NNF_Feature featureA, @NonNull final NNF_Feature featureB) {
        return recognizer.CompareFeature(session, featureA, featureB);
    }

    public void release() {
        initializer.ReleaseContext(session);
    }

    private void logResult(@NonNull final NNF_RESULT result, @NonNull final String method, @NonNull final String what) {
        Log.println(NNF_RESULT.FSUCCESS == result ? Log.DEBUG : Log.ERROR, getClass().getSimpleName(), String.format("%s(): %s Result number = %d, name = %s.", method, what, result.getValue(), result.name()));
    }

    @NonNull
    public KitInit getInitializer() {
        return initializer;
    }

    @NonNull
    public NNF_ActiveInfo getActivation() {
        return activation;
    }

    @NonNull
    public KitDetection getDetector() {
        return detector;
    }

    @NonNull
    public KitRecognition getRecognizer() {
        return recognizer;
    }

    @NonNull
    public NNF_Context getSession() {
        return session;
    }

    @NonNull
    public NNF_Function getFunction() {
        return function;
    }

    public static class Builder {

        public Builder() {
            context = new RecognitionContext();
            imageMode().cpu().threadNumber(1).faceDetectThreshold(0.6F).maxnum(10).minface(40).deviceIndex(0);
        }

        public RecognitionContext build() {
            return context;
        }

        public Builder imageMode() {
            context.detectionMode = NNF_DETECTIONMODE.IMAGE;
            return this;
        }

        public Builder videoMode() {
            context.detectionMode = NNF_DETECTIONMODE.VIDEO;
            return this;
        }

        public Builder threadNumber(final int threadNumber) {
            context.threadNumber = threadNumber;
            return this;
        }

        public Builder faceDetectThreshold(final float faceDetectThreshold) {
            context.faceDetectThreshold = faceDetectThreshold;
            return this;
        }

        public Builder maxnum(final int maxnum) {
            context.maxnum = maxnum;
            return this;
        }

        public Builder minface(final int minface) {
            context.minface = minface;
            return this;
        }

        public Builder deviceIndex(final int deviceIndex) {
            context.deviceIndex = deviceIndex;
            return this;
        }

        public Builder cpu() {
            context.device = NNF_DEVICE.CPU;
            return this;
        }

        public Builder gpu() {
            context.device = NNF_DEVICE.GPU;
            return this;
        }

        public Builder npu() {
            context.device = NNF_DEVICE.NPU;
            return this;
        }

        @NonNull
        private final RecognitionContext context;
    }
}
